﻿using System;
using System.Web.Mvc;
using Kratos.Framework.Extensions;
using Microsoft.Practices.Unity;

namespace Kratos.Framework.Filters
{
    public class KratosFilterAttribute : FilterAttribute, IAuthorizationFilter, IActionFilter, IResultFilter
    {
        private readonly IUnityContainer _container;

        private readonly Type _filterType;
        private object _filterInstance;

        public KratosFilterAttribute(Type filterType)
        {
            if (!IsFilterType(filterType))
                throw new Exception("'{0}' 不是FilterAttribute".With(filterType.Name));
            _filterType = filterType;
            _container = DependencyResolver.Current.GetService<IUnityContainer>();
        }

        private T ResolveFilterFromType<T>() where T : class
        {
            if (_filterInstance == null)
            {
                _filterInstance = _container.Resolve(_filterType);
            }
            return _filterInstance as T;
        }

        private void ExecuteFilterWhenItIs<TFilter>(Action<TFilter> action) where TFilter : class
        {
            var filter = ResolveFilterFromType<TFilter>();

            if (filter != null)
            {
                action(filter);
            }
        }

        public virtual void OnActionExecuting(ActionExecutingContext filterContext)
        {
            ExecuteFilterWhenItIs<IActionFilter>(f => f.OnActionExecuting(filterContext));
        }

        public virtual void OnActionExecuted(ActionExecutedContext filterContext)
        {
            ExecuteFilterWhenItIs<IActionFilter>(f => f.OnActionExecuted(filterContext));
        }

        public virtual void OnResultExecuting(ResultExecutingContext filterContext)
        {
            ExecuteFilterWhenItIs<IResultFilter>(f => f.OnResultExecuting(filterContext));
        }

        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            ExecuteFilterWhenItIs<IResultFilter>(f => f.OnResultExecuted(filterContext));
        }

        public virtual void OnAuthorization(AuthorizationContext filterContext)
        {
            ExecuteFilterWhenItIs<IAuthorizationFilter>(f => f.OnAuthorization(filterContext));
        }

        private bool IsFilterType(Type type)
        {
            return typeof(IActionFilter).IsAssignableFrom(type) ||
                   typeof(IResultFilter).IsAssignableFrom(type) ||
                   typeof(IAuthorizationFilter).IsAssignableFrom(type);
        }
    }
}
